import base64
import pickle

from django.shortcuts import render
from django_redis import get_redis_connection
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView

import constants
from carts.serializers import CartSerializer, CartSKUSerializer, CartDeleteSerializer, CartSelectAllSerializer
from goods.models import SKU


class CartView(APIView):
    """
    购物车数据哈希
    key: cart_用户id
    value: {sku_id:count, sku_id: count}

    购物车勾选记录-Set类型
    key: cart_selected_用户id
    value: {sku_id, sku_id}

    cookie中
    {
        sku_id: {
            "count": xxx,  // 数量
            "selected": True  // 是否勾选
        },
        sku_id: {
            "count": xxx,
            "selected": False
        },
        ...
    }
    pickle模块 .dumps()  .loads()
    base64模块 .b64encode()  .b64decode()
    """
    def get(self, request):
        """获取购物车信息"""
        user = request.user
        if user.is_authenticated():
            # 登录用户，从redis中获取购物车信息
            user_id = user.id
            redis_conn = get_redis_connection('cart')
            sku_ids = redis_conn.hkeys('cart_%s' % user_id)
            cart_list = []
            if sku_ids:
                for sku_id in sku_ids:
                    sku = SKU.objects.get(id=sku_id)
                    count = redis_conn.hget('cart_%s' % user_id, sku_id)
                    sku.count = int(count)
                    if sku_id in redis_conn.smembers('cart_selected_%s' % user_id):
                        sku.selected = True
                    else:
                        sku.selected = False
                    cart_list.append(sku)
        else:
            # 游客，从cookie中获取购物车信息
            cookie_cart = request.COOKIES.get('cart')
            cart_list = []
            if cookie_cart:
                cart = pickle.loads(base64.b64decode(cookie_cart.encode()))
                sku_ids = cart.keys()
                for sku_id in sku_ids:
                    sku = SKU.objects.get(id=sku_id)
                    sku.count = cart[sku_id]['count']
                    sku.selected = cart[sku_id]['selected']
                    cart_list.append(sku)

        # if user.is_authenticated():  # 用户已登录，从redis中读取
        #     redis_conn = get_redis_connection('cart')
        #     dict_cart = redis_conn.hgetall('cart_%s' % user.id)  # {1: 2, 2: 2}
        #     list_cart_selected = redis_conn.smembers('cart_selected_%s' % user.id)
        #
        #     # 拼装字典
        #     # {1:{'count':2, 'selected':False}, 2:{'count':2, 'selected':False}}
        #     cart = {}
        #     for sku_id, count in dict_cart.items():
        #         cart[int(sku_id)] = {
        #             'count': int(count),
        #             'selected': sku_id in list_cart_selected
        #         }
        # else:
        #     # 用户未登录，从cookie中读取
        #     cart = request.COOKIES.get('cart')
        #     if cart is not None:
        #         # 购物车base64字符串 --> 字典
        #         cart = pickle.loads(base64.b64decode(cart.encode()))
        #         # {1: {'count':2, 'selected':False}, 2: {'count':2, 'selected':False}}
        #         print('cookie: ', cart)
        #     else:
        #         cart = {}
        #
        #         # 查询购物车中所有的商品
        # cart_list = SKU.objects.filter(id__in=cart.keys())
        # for sku in cart_list:
        #     # 给sku对象新增两个字段: 商品数量和勾选状态
        #     sku.count = cart[sku.id]['count']
        #     sku.selected = cart[sku.id]['selected']

        # 从redis中取出购物车信息
        serializer = CartSKUSerializer(cart_list, many=True)
        return Response(serializer.data)

    def post(self, request):
        # 校验参数
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取参数
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')

        user = request.user
        if user.is_authenticated():
            # 已登录，购物车信息存在redis中
            user_id = user.id
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 存储购物车数据
            # pl.srem('cart_%s' % user_id)
            # pl.hset('cart_%s' % user_id, sku_id, count)
            # 有累加效果不用删除
            pl.hincrby('cart_%s' % user_id, sku_id, count)
            # 存储购物车商品勾选信息
            if selected:
                print(1)
                # 勾选便存储
                pl.sadd('cart_selected_%s' % user_id, sku_id)
            pl.execute()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            # 未登录状态，购物车信息存在cookie中
            # 从cookie中获取购物车信息
            cart = request.COOKIES.get('cart')
            if cart:
                # base64字符串 -> 字典
                cart = pickle.loads(base64.b64decode(cart.encode()))

            else:
                # 新建cart
                cart = {}
            # 向cart中增加购物车信息
            sku = cart.get(sku_id)
            if sku:
                count += int(sku.get('count'))

            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 字典 --> base64字符串
            cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
            response = Response(serializer.data, status=status.HTTP_201_CREATED)
            # 设置cookie
            response.set_cookie('cart', cookie_cart, constants.CART_COOKIE_EXPIRES)
            return response

    def put(self, request):
        # 修改购物车数据
        serializer = CartSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取参数
        sku_id = serializer.validated_data.get('sku_id')
        count = serializer.validated_data.get('count')
        selected = serializer.validated_data.get('selected')

        user = request.user
        print(user)
        if user.is_authenticated():
            # 已登录，购物车信息存在redis中
            user_id = user.id
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            # 存储购物车数据
            # pl.srem('cart_%s' % user_id)
            # pl.hset('cart_%s' % user_id, sku_id, count)
            # 有累加效果不用删除
            pl.hset('cart_%s' % user_id, sku_id, count)
            # 存储购物车商品勾选信息
            if selected:
                # 勾选便存储
                pl.sadd('cart_selected_%s' % user_id, sku_id)
            pl.execute()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            # 未登录状态，购物车信息存在cookie中
            # 从cookie中获取购物车信息
            cart = request.COOKIES.get('cart')
            if cart:
                # base64字符串 -> 字典
                cart = pickle.loads(base64.b64decode(cart.encode()))

            else:
                # 新建cart
                cart = {}
            # 向cart中增加购物车信息

            cart[sku_id] = {
                'count': count,
                'selected': selected
            }
            # 字典 --> base64字符串
            cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
            response = Response(serializer.data, status=status.HTTP_201_CREATED)
            # 设置cookie
            response.set_cookie('cart', cookie_cart, constants.CART_COOKIE_EXPIRES)
            return response

    def delete(self, request):
        # 删除购物车数据
        serializer = CartDeleteSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        # 获取参数
        sku_id = serializer.validated_data.get('sku_id')

        user = request.user
        if user.is_authenticated():
            # 登录用户删除购物车从redis中
            user_id = user.id
            redis_conn = get_redis_connection('cart')
            pl = redis_conn.pipeline()
            pl.hdel('cart_%s' % user_id, sku_id)
            pl.srem('cart_selected_%s' % user_id, sku_id)
            pl.execute()
            return Response(status=status.HTTP_204_NO_CONTENT)
        else:
            # 游客删除购物车从cookie中
            response = Response(status=status.HTTP_204_NO_CONTENT)
            cookie_cart1 = request.COOKIES.get('cart')
            if cookie_cart1:
                cart = pickle.loads(base64.b64decode(cookie_cart1.encode()))
                if sku_id in cart:
                    del cart[sku_id]
                    cookie_cart2 = base64.b64encode(pickle.dumps(cart)).decode()
                    response.set_cookie('cart', cookie_cart2, constants.CART_COOKIE_EXPIRES)
            return response

    def perform_authentication(self, request):
        """
       drf框架在视图执行前会调用此方法进行身份认证(jwt认证)
       如果认证不通过,则会抛异常返回401状态码
       抛异常会导致视图无法执行，可以在此处捕获异常
       """
        try:
            super(CartView, self).perform_authentication(request)
        except Exception:
            pass


class CartSelectAllView(APIView):
    """购物车全选视图"""
    def put(self, request):
        serializer = CartSelectAllSerializer(data=request.data)
        serializer.is_valid()

        selected = serializer.validated_data.get('selected')

        user = request.user
        if user.is_authenticated():
            # 登录用户全选操作redis
            user_id = user.id
            redis_conn = get_redis_connection('cart')

            # pl = redis_conn.pipeline()
            sku_ids = redis_conn.hkeys('cart_%s' % user_id)
            # sku_ids = pl.hkeys('cart_%s' % user_id)
            # 下面要用到sku_ids所以不能用管道
            if selected:
                redis_conn.sadd('cart_selected_%s' % user_id, *sku_ids)
                # pl.sadd('cart_selected_%s' % user_id, *sku_ids)
            else:
                redis_conn.srem('cart_selected_%s' % user_id, *sku_ids)
                # pl.srem('cart_selected_%s' % user_id, *sku_ids)
            # pl.execute()

            return Response({'message': 'OK'})
        else:
            # 游客全选操作cookie
            response = Response({'message': 'OK'})
            cart = request.COOKIES.get('cart')
            if cart:
                cart = pickle.loads(base64.b64decode(cart.encode()))
                sku_ids = cart.keys()
                for sku_id in sku_ids:
                    cart[sku_id]['selected'] = selected
                cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
                response.set_cookie('cart', cookie_cart, constants.CART_COOKIE_EXPIRES)
            return response

    def perform_authentication(self, request):
        try:
            super(CartSelectAllView, self).perform_authentication(request)
        except Exception:
            pass
